#include "FeatureExtractor.h"
#include <iostream>
#include <cmath>


// 提取 SIFT 特征函数（返回关键点和描述子）
std::pair<std::vector<cv::KeyPoint>, cv::Mat> extractSIFT(const cv::Mat& image) {
    //auto* result = new std::pair<std::vector<cv::KeyPoint>, cv::Mat>();
	// 创建 SIFT 检测器
    cv::Ptr<cv::SIFT> detector = cv::SIFT::create();
    
    // 检测关键点并计算描述子
    std::vector<cv::KeyPoint> keypoints;
    cv::Mat descriptors;
    detector->detectAndCompute(image, cv::noArray(), keypoints, descriptors);
    
    // 返回关键点和描述子
   return std::make_pair(keypoints, descriptors);
    //return result;
}

std::vector<double> extractHuMoments(const cv::Mat& image) {
    // 转换为灰度图像
    cv::Mat grayImg;
    cv::cvtColor(image, grayImg, cv::COLOR_BGR2GRAY);
 
    // 计算Hu矩
    cv::Moments moments = cv::moments(grayImg);
    cv::Mat hu;
    cv::HuMoments(moments, hu);
 
    // 处理Hu矩数值
    std::vector<double> processedHuMoments;
    for (int i = 0; i < 7; ++i) {
        double val = hu.at<double>(i);
        processedHuMoments.push_back(
            std::copysign(1.0, val) * std::log10(std::abs(val) + 1e-10)
        );
    }
 
    return processedHuMoments;
}

GeometricFeatures extractGeometricFeatures(const cv::Mat& image) {
    cv::Mat grayImg;
    // 转换为灰度图
    if (image.channels() == 3) {
        cv::cvtColor(image, grayImg, cv::COLOR_BGR2GRAY);
    } else {
        grayImg = image.clone();
    }
    // 高斯模糊去噪
    cv::GaussianBlur(grayImg, grayImg, cv::Size(5,5), 0);
    // 自适应二值化（Otsu）
    cv::threshold(grayImg, grayImg, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);
    // 形态学闭合填充缺口
    cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(5,5));
    cv::morphologyEx(grayImg, grayImg, cv::MORPH_CLOSE, kernel);
    // 提取轮廓
    std::vector<std::vector<cv::Point>> contours;
    cv::findContours(grayImg, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
    GeometricFeatures features = {0.0, 0.0, 0.0};
    if (!contours.empty()) {
        // 按面积排序，选择最大轮廓
        std::sort(contours.begin(), contours.end(),
            [](const std::vector<cv::Point>& a, const std::vector<cv::Point>& b) {
                return cv::contourArea(a) > cv::contourArea(b);
            });
        const auto& largestContour = contours[0];
        
        // 计算几何特征
        features.area = cv::contourArea(largestContour);
        features.perimeter = cv::arcLength(largestContour, true);
        // 计算最小外接矩形宽高比
        cv::RotatedRect rect = cv::minAreaRect(largestContour);
        features.aspectRatio = (rect.size.width > rect.size.height) ?
            rect.size.width / rect.size.height : 
            rect.size.height / rect.size.width; // 确保 >=1
    } else {
        std::cerr << "警告：未检测到轮廓，请检查输入图像！" << std::endl;
    } 
    return features;
}


std::array<double, 3> extractZoneDensity(const cv::Mat& image) {
    cv::Mat grayImg;
    cv::cvtColor(image, grayImg, cv::COLOR_BGR2GRAY);
    cv::threshold(grayImg, grayImg, 128, 255, cv::THRESH_BINARY);
 
    const int w = grayImg.cols;
    const int h = grayImg.rows;
    const cv::Point center(w/2, h/2);
    
    // 定义环形区域半径（示例为3个环形区域）
    const int radius1 = std::min(w, h) / 4;  // 内圆半径
    const int radius2 = std::min(w, h) / 2;  // 中环半径
    const int radius3 = std::min(w, h) * 3/4; // 外圆半径
 
    // 创建环形掩膜
    cv::Mat mask1 = cv::Mat::zeros(grayImg.size(), CV_8U);
    cv::Mat mask2 = cv::Mat::zeros(grayImg.size(), CV_8U);
    cv::Mat mask3 = cv::Mat::zeros(grayImg.size(), CV_8U);
    
    // 内圆区域（0 < r < radius1）
    cv::circle(mask1, center, radius1, 255, cv::FILLED);
    
    // 中环区域（radius1 < r < radius2）
    cv::circle(mask2, center, radius2, 255, cv::FILLED);
    cv::circle(mask2, center, radius1, 0, cv::FILLED);
    
    // 外圆区域（radius2 < r < radius3）
    cv::circle(mask3, center, radius3, 255, cv::FILLED);
    cv::circle(mask3, center, radius2, 0, cv::FILLED);
 
    // 计算各环形区域的像素密度
    std::array<double, 3> densities;
    densities[0] = cv::mean(grayImg, mask1)[0]; // 内圆密度
    densities[1] = cv::mean(grayImg, mask2)[0]; // 中环密度
    densities[2] = cv::mean(grayImg, mask3)[0]; // 外圆密度
 
    return densities;
}

std::string extractcolor(const cv::Mat& image)
{
	
   // cv::imshow("Image Display", img);
    //cv::waitKey(0);

    // 转换为 HSV 空间
    cv::Mat hsvImg;
    cv::cvtColor(image, hsvImg, cv::COLOR_BGR2HSV);

    // 判断颜色（红色或黑色）
    const int minSaturation = 40;  // 最小饱和度阈值
    const int minValue = 30;       // 最小亮度阈值
    const float redThreshold = 0.3; // 红色像素比例阈值

    int redCount = 0;
    int validPixels = 0;

    // 遍历所有像素
    for (int i = 0; i < hsvImg.rows; ++i) {
        for (int j = 0; j < hsvImg.cols; ++j) {
            cv::Vec3b hsv = hsvImg.at<cv::Vec3b>(i, j);

            // 过滤无效像素（低饱和度或低亮度）
            if (hsv[1] > minSaturation && hsv[2] > minValue) {
               ++validPixels;

                // Hue值范围处理（OpenCV将Hue缩放到0-180）
                if ((hsv[0] <= 10) || (hsv[0] >= 160)) { // 红色范围
                    ++redCount;
                }
            }
        }
    }

    // 打印调试信息
    std::cout << "图像总像素数: " << image.total() << std::endl;
    std::cout << "有效像素数 (validPixels): " << validPixels << std::endl;
    std::cout << "红色像素数 (redCount): " << redCount << std::endl;

/*
    // 有效像素比例不足时抛出异常
    if (validPixels < img.total() * 0.1) {
        throw std::runtime_error("图像有效颜色区域不足");
    }
*/
    // 计算红色像素比例
    float redRatio = static_cast<float>(redCount) / validPixels;
    std::string color = redRatio > redThreshold ? "red" : "black";

    std::cout << "红色像素比例 (redRatio): " << redRatio << std::endl;
    std::cout << "识别颜色: " << color << std::endl;
	return color;
}


//多态特征提取，这个可以输入图像也可以（输入mat不是path）
ChessDatabase::ChessPiece extractChessPieceFeatures(
    const std::string& imagePath,
    double x,
    double y,
    const std::string& type)
{
    // 加载图像（彩色模式）
    cv::Mat img = cv::imread(imagePath, cv::IMREAD_COLOR);
    if (img.empty()) {
        throw std::runtime_error("无法加载图像: " + imagePath);
    } 
// 调用封装后的各个特征的提取函数
    std::vector<double> huMoments = extractHuMoments(img);
    std::string color=extractcolor(img);
	//std::vector<double> projHist=extractProjectionHistogram(img);
	std::array<double, 3> zoneDensity=extractZoneDensity(img);
	GeometricFeatures temporary=extractGeometricFeatures(img);
	// 提取 SIFT 特征
	std::cout<<"begin to extract sift"<<std::endl;
	// 使用后记得释放内存
	auto siftResult = extractSIFT(img);

    //auto siftResult = extractSIFT(img);
	std::cout<<"end to extract sift"<<std::endl;
    // 构造棋子特征对象
    ChessDatabase::ChessPiece piece;
    piece.x = x;
    piece.y = y;
    piece.color = color; // 自动识别的颜色
    piece.type = type;
	piece.area=temporary.area;
	piece.perimeter=temporary.perimeter;
	piece.aspectRatio=temporary.aspectRatio;
	piece.zoneDensity=zoneDensity;
	piece.siftKeypoints = siftResult.first;   // 存储关键点
    piece.siftDescriptors = siftResult.second; // 存储描述子
	//piece.siftKeypoints = std::move(siftResult->first);
	//piece.siftDescriptors = std::move(siftResult->second);
	//delete siftResult;
// 将提取的Hu矩复制到结构体中
    for (int i = 0; i < 7; ++i) {
        piece.huMoments[i] = huMoments[i];
    }
	
    return piece;
}




//多态特征提取，这个可以输入图像也可以（输入mat不是path）
ChessDatabase::ChessPiece extractChessPieceFeatures(
    cv::Mat img,
    double x,
    double y,
    const std::string& type)
{
    
// 调用封装后的各个特征的提取函数
    std::vector<double> huMoments = extractHuMoments(img);
    std::string color=extractcolor(img);
	//std::vector<double> projHist=extractProjectionHistogram(img);
	std::array<double, 3> zoneDensity=extractZoneDensity(img);
	GeometricFeatures temporary=extractGeometricFeatures(img);
	// 提取 SIFT 特征
	std::cout<<"begin to extract sift"<<std::endl;
	// 使用后记得释放内存
	//auto* siftResult = extractSIFT(img);

    //auto siftResult = extractSIFT(img);
	std::cout<<"end to extract sift"<<std::endl;
    // 构造棋子特征对象
    ChessDatabase::ChessPiece piece;
    piece.x = x;
    piece.y = y;
    piece.color = color; // 自动识别的颜色
    piece.type = type;
	piece.area=temporary.area;
	piece.perimeter=temporary.perimeter;
	piece.aspectRatio=temporary.aspectRatio;
	piece.zoneDensity=zoneDensity;
	//piece.siftKeypoints = siftResult.first;   // 存储关键点
   // piece.siftDescriptors = siftResult.second; // 存储描述子
	//piece.siftKeypoints = std::move(siftResult->first);
	//piece.siftDescriptors = std::move(siftResult->second);
	//delete siftResult;
// 将提取的Hu矩复制到结构体中
    for (int i = 0; i < 7; ++i) {
        piece.huMoments[i] = huMoments[i];
    }
	
    return piece;
}
